# models/user_models.py
from .base import db, BaseModel
from flask_bcrypt import Bcrypt
import jwt
from datetime import datetime, timedelta
import uuid
from sqlalchemy.types import TypeDecorator, String
from config.development import DevelopmentConfig as Config
from sqlalchemy import UniqueConstraint

# 自定义UUID类型转换器
class UUIDString(TypeDecorator):
    impl = String(36)
    cache_ok = True  # 添加此属性以消除缓存警告

    def process_bind_param(self, value, dialect):
        if value is None:
            return None
        if isinstance(value, uuid.UUID):
            return str(value)
        return value

    def process_result_value(self, value, dialect):
        if value is None:
            return None
        try:
            return uuid.UUID(value)
        except ValueError:
            return value


bcrypt = Bcrypt()

class User(BaseModel):
    """用户模型，包含认证相关字段"""
    __tablename__ = "users"
    
    id = db.Column(UUIDString, primary_key=True)  # 使用自定义UUID类型转换器
    username = db.Column(db.String(80), unique=True, nullable=False)
    password_hash = db.Column(db.String(128), nullable=False)
    public_key = db.Column(db.Text, unique=True, nullable=True)
    is_active = db.Column(db.Boolean, default=True)
    encrypted_master_key = db.Column(db.String(255), nullable=False)
    kek_salt = db.Column(db.String(64), nullable=False)
    user_role = db.Column(db.String(20), nullable=False, default='user')
    failed_login_attempts = db.Column(db.Integer, default=0)
    failed_login_at = db.Column(db.DateTime, nullable=True)
    login_locked_until = db.Column(db.DateTime, nullable=True)
    last_login = db.Column(db.DateTime, nullable=True)
    online = db.Column(db.Boolean, default=False)

    def set_password(self, password):
        """加密密码"""
        self.password_hash = bcrypt.generate_password_hash(password).decode('utf-8')
    
    def check_password(self, password):
        """验证密码"""
        return bcrypt.check_password_hash(self.password_hash, password)
    
    def generate_jwt(self, expires_hours=24):
        """生成JWT令牌"""
        payload = {
            'user_id': self.id,
            'exp': datetime.utcnow() + timedelta(hours=expires_hours)
        }
        return jwt.encode(payload, Config.SECRET_KEY, algorithm='HS256')
    
    @staticmethod
    def decode_jwt(token):
        """解析JWT令牌"""
        try:
            payload = jwt.decode(token, Config.SECRET_KEY, algorithms=['HS256'])
            return payload['user_id']
        except jwt.ExpiredSignatureError:
            return None
        except jwt.InvalidTokenError:
            return None


class Friendship(BaseModel):
    """好友关系模型，管理用户之间的好友关系"""
    __tablename__ = "friendships"
    
    # 使用复合主键确保关系的唯一性
    __table_args__ = (
        UniqueConstraint('user_id', 'friend_id', name='unique_friendship'),
    )
    
    id = db.Column(db.String(36), primary_key=True)
    user_id = db.Column(UUIDString, db.ForeignKey('users.id'), nullable=False)
    friend_id = db.Column(UUIDString, db.ForeignKey('users.id'), nullable=False)
    status = db.Column(db.String(20), default='pending')  # pending, accepted, blocked
    
    # 关联关系
    user = db.relationship('User', foreign_keys=[user_id], backref='friendships')
    friend = db.relationship('User', foreign_keys=[friend_id], backref='friend_of')
    
    @classmethod
    def create_friend_request(cls, user_id, friend_id):
        """创建好友请求"""
        # 检查是否已经存在好友关系
        existing = cls.query.filter(
            ((cls.user_id == user_id) & (cls.friend_id == friend_id)) |
            ((cls.user_id == friend_id) & (cls.friend_id == user_id))
        ).first()
        
        if existing:
            return existing
        
        # 创建新的好友请求
        friendship = cls(
            id=str(uuid.uuid4()),
            user_id=user_id,
            friend_id=friend_id,
            status='pending'
        )
        db.session.add(friendship)
        db.session.commit()
        return friendship
    
    @classmethod
    def accept_friend_request(cls, user_id, friend_id):
        """接受好友请求"""
        friendship = cls.query.filter(
            (cls.user_id == friend_id) & (cls.friend_id == user_id) &
            (cls.status == 'pending')
        ).first()
        
        if friendship:
            friendship.status = 'accepted'
            db.session.commit()
            return friendship
        return None
    
    @classmethod
    def get_friends(cls, user_id):
        """获取用户的所有好友"""
        friendships = cls.query.filter(
            ((cls.user_id == user_id) | (cls.friend_id == user_id)) &
            (cls.status == 'accepted')
        ).all()
        
        friends = []
        for fs in friendships:
            if fs.user_id == user_id:
                friends.append(fs.friend)
            else:
                friends.append(fs.user)
        
        return friends
    
    @classmethod
    def is_friends(cls, user_id, friend_id):
        """检查两个用户是否是好友"""
        return cls.query.filter(
            ((cls.user_id == user_id) & (cls.friend_id == friend_id)) |
            ((cls.user_id == friend_id) & (cls.friend_id == user_id))
        ).filter(cls.status == 'accepted').first() is not None